`timescale 1ns/1ps

module tb;
  // ------------------------------
  // 1) 时钟与复位
  // ------------------------------
  reg clk  = 1'b0;  // 主时钟
  reg rstn = 1'b0;  // 同步复位，低有效

  // 时钟：10ns 周期
  always #5 clk = ~clk;

  // 便捷任务：等待 n 个上升沿
  task wait_cycles(input integer n);
    integer k; begin for (k=0;k<n;k=k+1) @(posedge clk); end
  endtask

  // ------------------------------
  // 2) DUT 实例化
  // ------------------------------
  // 与工程中的 cpu_top.v 端口保持一致；imem 在 tb 内部加载。
  cpu_top dut (
    .clk (clk),
    .rstn(rstn)
  );

  // ------------------------------
  // 3) 仿真激励流程
  // ------------------------------
  initial begin
    // 3.1 导出波形（可用 gtkwave 查看）
    $dumpfile("cpu_addi.vcd");
    $dumpvars(0, tb);

    // 3.2 在复位之前，把程序加载进 DUT 的指令 ROM
    //     注意层次路径：dut.u_imem.mem —— 与 cpu_top 中 imem 实例名一致
    $display("TB: loading prog.hex into dut.u_imem.mem ...");
    $readmemh("prog.hex", dut.u_imem.mem);

    // 3.3 同步复位：保持 rstn=0 跨过 >=1 个时钟上升沿
    rstn = 1'b0; wait_cycles(2);
    rstn = 1'b1;

    // 3.4 运行若干拍（包含 NOP 以排空流水线）
    //     根据程序长度与流水深度适当放宽，这里给 30 拍
    wait_cycles(30);

    // ------------------------------
    // 4) 结果检查（简单断言）
    // ------------------------------
    // 预期（示例 prog.hex 对应）：
    //   x1 = 5
    //   x2 = 7
    //   x3 = 12
    //   x4 = 7
    if (dut.u_rf.regs[1] !== 32'd5)   $fatal(1, "x1 exp=5, got=0x%08x",  dut.u_rf.regs[1]);
    if (dut.u_rf.regs[2] !== 32'd7)  $fatal(1, "x2 exp=7, got=0x%08x", dut.u_rf.regs[2]);
    if (dut.u_rf.regs[3] !== 32'd12)  $fatal(1, "x3 exp=12, got=0x%08x", dut.u_rf.regs[3]);
    if (dut.u_rf.regs[4] !== 32'd7)  $fatal(1, "x4 exp=7, got=0x%08x", dut.u_rf.regs[4]);

    $display("[PASS] ADDI ADD SUB pipeline ok.");
    $finish;
  end
endmodule
